<template>
  <n-card :bordered="false" class="proCard">
    <n-spin :show="loading">
      <div class="basicInfo">
        <div class="basicInfo-body-wrapper">
          <div
            v-for="(item, key) in detailList"
            :key="key"
            :class="[
              'basicInfo-view',
              routerType === 'check' ? 'basicInfo-view-check' : '',
              item.class ? item.class : '',
            ]"
          >
            <div v-if="!item.hiddenTitle" class="basicInfo-header">
              <h3>{{ item.title || $t('common.form.basicInfo') }}</h3>
            </div>

            <template v-if="item.type === 'slot'">
              <slot :name="item.slotName"></slot>
            </template>

            <template v-else-if="item.type === 'form'">
              <DFDescriptions
                v-if="routerType === 'check'"
                :ref="
                  (el) => {
                    setDetailRefFn(el, item.ref || `dfFormRef${key}`, item.type);
                  }
                "
                :getLabelForm="item.getLabelForm || detailGetLabelForm"
                :column="item.formCols || item.descriptionsColumn || detailFormCols"
                :routeName="item.routeName || detailRouteName"
                :label-width="
                  item.labelWidth || item.descriptionsLabelWidth || descriptionsLabelWidth
                "
                :descriptionsList="item.descriptionsList || item.descriptionsSchemas || []"
              >
                <template v-for="(_, slot) in $slots" #[slot]="{ model }">
                  <slot :name="slot" :model="model"></slot>
                </template>
              </DFDescriptions>

              <DFForm
                v-else
                :ref="
                  (el) => {
                    setDetailRefFn(el, item.ref || `dfFormRef${key}`, item.type);
                  }
                "
                :getLabelForm="item.getLabelForm || detailGetLabelForm"
                :label-width="item.labelWidth || detailFormLabelWidth"
                :routeName="item.routeName || detailRouteName"
                @register="item.register"
              >
                <template v-for="(_, slot) in $slots" #[slot]="{ model }">
                  <slot :name="slot" :model="model"></slot>
                </template>
              </DFForm>
            </template>

            <DFTable
              v-else-if="item.type === 'table'"
              :ref="
                (el) => {
                  setDetailRefFn(el, item.ref || `dfTableRef${key}`, item.type);
                }
              "
              :columns="item.columns"
              :isEditTable="true"
              :routeName="item.routeName || detailRouteName"
              :showAddAndDelBtn="
                item.showAddAndDelBtn === undefined ? tableShowAddAndDelBtn : item.showAddAndDelBtn
              "
              :pagination="item.pagination === undefined ? true : item.pagination"
              @updateCheck="item.onCheckedRowFn"
              @editTableDataChangeFn="item.editTableDataChangeFn"
            />
          </div>
        </div>
      </div>
      <div
        v-if="detailList && detailList.length && !hiddenBottomBtn"
        class="basicInfo-bottom defaultButtonClass"
      >
        <div>
          <n-button
            @click="handleBackFn"
            class="add-btn"
            :type="routerType !== 'check' ? 'default' : 'primary'"
          >
            {{ $t('common.button.back') }}</n-button
          >
          <n-button
            type="primary"
            v-if="routerType !== 'check'"
            :loading="saveLoading"
            @click="handleSubmitFn"
            class="add-btn"
          >
            {{ $t('common.button.save') }}</n-button
          >
        </div>
      </div>
    </n-spin>
  </n-card>
</template>

<script lang="ts" setup name="DFPageDetail">
  import { DFTable } from '@/components/DFTable';
  import { DFForm, useForm } from '@/components/DFForm/index';
  import { setFormSchemasFn } from '@/utils/df/form';
  import { useMixins } from '@/hooks/useMixins';
  import { setTableColumnsFn } from '@/utils/df/table';
  import { useRoute } from 'vue-router';

  type Props = {
    pageOptions?: {
      list?: any[];
      requestFn?: Function; // table请求方法
    };
  };

  const route = useRoute();

  const props = withDefaults(defineProps<Props>(), {
    pageOptions: () => ({}),
  });

  const {
    language,
    routerPage,
    t,
    getPageLangValueFn,
    message,
    routerType = 'add',
    toBackFn,
    backPath,
    router,
    cloneDeep,
    detailListName,
    getTableLabelFn,
    clearKeepAliveFn,
  } = useMixins();

  const loading = ref(false);

  const saveLoading = ref(false);

  const detailList: any = ref([]);

  const detailRefList: any = [];

  const hiddenBottomBtn = ref(false);

  const setDetailRefFn = (el: any, name: any, type: any) => {
    if (el) {
      const obj = {
        name,
        el,
        type,
      };

      const isAdd = detailRefList.every((item, key) => {
        if (item.name === name) {
          detailRefList[key] = obj;

          return false;
        }

        return true;
      });

      if (isAdd) {
        detailRefList.push(obj);
      }
    }
  };

  const detailFormCols = ref(3); // 表格一行几列

  const detailFormLayout = ref('horizontal'); // 表单展示类型（横向/纵向）

  let detailFormLabelWidthZh = 80; // 表单label宽度

  let detailFormLabelWidthEn = 80; // 表单label宽度

  const detailFormLabelWidth = computed(() =>
    language.value === 'zh' ? detailFormLabelWidthZh : detailFormLabelWidthEn
  );

  let descriptionsLabelWidthZh = 80; // 查看列表label宽度

  let descriptionsLabelWidthEn = 80; // 查看列表label宽度

  const descriptionsLabelWidth = computed(() =>
    language.value === 'zh' ? descriptionsLabelWidthZh : descriptionsLabelWidthEn
  );

  let detailGetLabelForm = 'table'; // 查看列表语言模块

  let detailRouteName = routerPage; // form国际化模块（默认当前页面）

  const checkRequireNotNullFn = (
    tableRef: any = {},
    tableName = 'tableName',
    routeName = detailRouteName
  ) => {
    let isSubmit = true;

    let errMsg: any = null;

    const { columns = [], getEditTableDataFn = null } = tableRef;

    // console.log(columns);

    if (getEditTableDataFn && columns && columns.length) {
      let notNull = `${t('common.tipMsg.notNull')}`;

      const requiredList: any = [];

      const data = unref(getEditTableDataFn()) || [];

      for (const item of columns) {
        const { required = false, key = null, ifShow = true } = item;

        if (required && key && ifShow) {
          requiredList.push(item);
        }
      }

      if (data && data.length) {
        isSubmit = data.every((item) => {
          const { index = null } = item;

          return requiredList.every((rItem) => {
            const { label = '', key = '' } = rItem;

            const val = item[key];

            if (!val && val !== 0) {
              let text = getTableLabelFn(rItem, routeName);

              console.log(text);

              console.log(rItem);
              // 英文缩写情况下不必转换为小写
              const abbreviationKeys = ['aql', 'accept', 'reject'];
              if (
                language.value === 'en' &&
                !abbreviationKeys.includes(label) &&
                !abbreviationKeys.includes(key)
              ) {
                text = text.toLowerCase();
              }

              notNull = notNull.replace('XXX', text);

              notNull = notNull.replace(
                'NO.',
                (language.value === 'en' ? 'NO.' : '') + index || ''
              );

              errMsg = notNull;

              return false;
            }

            return true;
          });
        });
      } else {
        isSubmit = false;

        errMsg = `${t('common.tipMsg.tableNotEmpty')}`;

        if (tableName === 'tableName') {
          errMsg = errMsg.replace(
            'tableName',
            routeName
              ? language.value === 'en'
                ? t(`${routeName}.table.${tableName}`).toLowerCase()
                : t(`${routeName}.table.${tableName}`)
              : getPageLangValueFn(`table.${tableName}`)
          );
        } else {
          errMsg = errMsg.replace('tableName', tableName);
        }
      }
    } else {
      isSubmit = false;
    }

    if (!isSubmit && errMsg) {
      message.error(errMsg);
    }

    return isSubmit;
  };

  const backFn: any = ref(null);

  const initData: any = ref(null);

  let detailBackPath = null;

  let detailRouteParamsKey = 'id';

  let getDetailsFnDataKey = 'data';

  let detailsData = {};

  let tableShowAddAndDelBtn = true;

  let tableHasSelection = true;

  const addFn: any = ref(null); // 新增方法

  const updateFn: any = ref(null); // 更新方法

  const getDetailsFn: any = ref(null); // 获取当前详情方法

  const handleEditDetailsFn: any = ref(null); // 手动处理获取当前详情数据方法

  const setGetDetailsDataFn: any = ref(null); // 设置获取当前详情入参方法

  const setDetailsDataFn: any = ref(null); // 设置数据方法

  const setDetailsSubmitDataFn: any = ref(null); // 设置提交数据方法

  const beforeDetailsSubmitFn: any = ref(null); // 提交之前方法

  const afterDetailsSubmitFn: any = ref(null); // 提交之后方法

  const handleDetailsSubmitFn: any = ref(null); // 手动处理提交数据的方法

  const handleDetailsSubmitErrorFn: any = ref(null); // 手动处理提交数据报错的方法

  const getDetailRefListDataFn = () => {
    const obj = {};

    if (detailRefList && detailRefList.length) {
      detailRefList.forEach((item, key) => {
        const { el = {}, type = null, name = null } = item;

        if (type === 'form' && routerType !== 'check') {
          obj[name || `dfFormRef${key}`] = el.getFieldsValueFn();
        }

        if (type === 'table') {
          obj[name || `dfTableRef${key}`] = el.getEditTableDataFn();
        }
      });
    }

    return obj;
  };

  const handleBackFn = async () => {
    if (backFn && backFn.value) {
      await backFn.value();
    } else {
      const { params = {} } = route;

      const id = params[detailRouteParamsKey];

      const data = getDetailRefListDataFn();

      toBackFn(
        routerType === 'check' ? null : id,
        route,
        toRaw(data),
        toRaw(initData.value),
        detailBackPath || backPath
      );
    }
  };

  const handleSubmitFn = async () => {
    saveLoading.value = true;

    if (detailRefList && detailRefList.length) {
      try {
        let isSubmit = true;

        const refData: any = {};

        let data: any = {};

        for (let i = 0; i < detailRefList.length; i++) {
          const { name = '', type = '', el = {}, tableName = 'tableName' } = detailRefList[i];

          if (type === 'form') {
            await el.validate();

            const formData = el.getFieldsValueFn();

            // console.log(JSON.parse(JSON.stringify(formData)));

            data = {
              ...data,
              ...formData,
            };

            refData[name] = formData;
          }

          if (type === 'table') {
            isSubmit = checkRequireNotNullFn(el, tableName);

            if (!isSubmit) {
              break;
            } else {
              const formData = el.getEditTableDataFn();

              data[name] = formData;

              refData[name] = formData;
            }
          }
        }

        if (isSubmit) {
          if (beforeDetailsSubmitFn.value) {
            // 提交之前方法
            isSubmit = await beforeDetailsSubmitFn.value(data, refData);
          }

          if (isSubmit) {
            let res: any = null;

            data = {
              ...detailsData,
              ...data,
            };

            if (setDetailsSubmitDataFn.value) {
              data = setDetailsSubmitDataFn.value(data, routerType, refData);
            }

            switch (routerType) {
              case 'add':
              case 'copy':
                // data['password'] = encrypt(data.password);

                res = await addFn.value(data);
                break;
              case 'edit':
                res = await updateFn.value(data);
                break;

              default:
                break;
            }

            if (handleDetailsSubmitFn.value) {
              handleDetailsSubmitFn.value(res);
            } else {
              if (res) {
                const { message: msg = '' } = res;

                msg && message.success(msg);

                if (afterDetailsSubmitFn.value) {
                  await afterDetailsSubmitFn.value(res);
                }

                detailListName && clearKeepAliveFn(detailListName);

                router.push(detailBackPath || backPath);
              }
            }
          }

          console.log('提交');
        }
      } catch (e) {
        console.log(e);
      }
    }

    saveLoading.value = false;
  };

  const setVarsFn = (pageOptions) => {
    if (pageOptions) {
      const {
        routeName = null,
        backPath = null,
        routeParamsKey = null,
        formCols = null,
        formLayout = null,
        formLabelWidthZh = null,
        formLabelWidthEn = null,
        getLabelForm = null,
        getDataFnDataKey = null,
        showAddAndDelBtn = null,
        hasSelection = null,
        descriptionsListLabelWidthZh = null,
        descriptionsListLabelWidthEn = null,
      } = pageOptions;

      routeName && (detailRouteName = routeName);

      backPath && (detailBackPath = backPath);

      routeParamsKey && (detailRouteParamsKey = routeParamsKey);

      formLabelWidthZh && (detailFormLabelWidthZh = formLabelWidthZh);

      formLabelWidthEn && (detailFormLabelWidthEn = formLabelWidthEn);

      getLabelForm && (detailGetLabelForm = getLabelForm);

      formCols && (detailFormCols.value = formCols);

      formLayout && (detailFormLayout.value = formLayout);

      formCols && (detailFormCols.value = formCols);

      getDataFnDataKey && (getDetailsFnDataKey = getDataFnDataKey);

      showAddAndDelBtn && (tableShowAddAndDelBtn = showAddAndDelBtn);

      hasSelection && (tableHasSelection = hasSelection);

      descriptionsListLabelWidthZh && (descriptionsLabelWidthZh = descriptionsListLabelWidthZh);

      descriptionsListLabelWidthEn && (descriptionsLabelWidthEn = descriptionsListLabelWidthEn);
    }
  };

  const setFunFn = (pageOptions: any = {}) => {
    if (pageOptions) {
      const {
        addDataFn = null,
        updateDataFn = null,
        getDataFn = null,
        handleEditDataFn = null,
        setGetDataDataFn = null,
        setDataDataFn = null,
        setSubmitDataFn = null,
        beforeSubmitFn = null,
        afterSubmitFn = null,
        handleSubmitFn = null,
        handleSubmitErrorFn = null,
      } = pageOptions;
      addDataFn && (addFn.value = addDataFn);

      updateDataFn && (updateFn.value = updateDataFn);

      getDataFn && (getDetailsFn.value = getDataFn);

      handleEditDataFn && (handleEditDetailsFn.value = handleEditDataFn);

      setGetDetailsDataFn && (setGetDetailsDataFn.value = setGetDataDataFn);

      setDataDataFn && (setDetailsDataFn.value = setDataDataFn);

      setSubmitDataFn && (setDetailsSubmitDataFn.value = setSubmitDataFn);

      beforeSubmitFn && (beforeDetailsSubmitFn.value = beforeSubmitFn);

      afterSubmitFn && (afterDetailsSubmitFn.value = afterSubmitFn);

      handleSubmitFn && (handleDetailsSubmitFn.value = handleSubmitFn);

      handleSubmitErrorFn && (handleDetailsSubmitErrorFn.value = handleSubmitErrorFn);
    }
  };

  // const handleDeleteFn = (_row) => {};

  const initFn = async (props) => {
    if (props) {
      const { pageOptions = {} } = props;

      const { list = [], hiddenBottomBtn: pHiddenBottomBtn = false } = pageOptions;

      if (pHiddenBottomBtn) {
        hiddenBottomBtn.value = true;
      }

      setVarsFn(pageOptions);

      setFunFn(pageOptions);

      for (const item of list) {
        const newItem = item;

        const {
          type = '',
          formSchemas = [],
          useFormObj = {},
          columns = [],
          hasSelection = null,
          showAddAndDelBtn = null,
          // addAndDelete = false,
          // operaColumn = null,
          // actionColumn = null,
        } = newItem;

        if (type === 'form' && formSchemas && formSchemas.length) {
          const schemas = setFormSchemasFn(formSchemas, routerType === 'edit');

          newItem.formSchemas = ref([]);

          newItem.formSchemas.value = schemas;

          newItem.descriptionsSchemas = schemas;

          const [
            register,
            {
              validate: validateFn,
              getFieldsValue: getFieldsValueFn,
              setFieldsValue: setFieldsValueFn,
              clearValidate: clearValidateFn,
            },
          ] = useForm({
            gridProps: { cols: detailFormCols as any },
            layout: detailFormLayout,
            showActionButtonGroup: false,
            ...useFormObj,
            schemas,
          }); // dialog表单配置方法

          newItem.fn = {
            validateFn,
            getFieldsValueFn,
            setFieldsValueFn,
            clearValidateFn,
          };

          newItem.register = register;

          detailList.value.push(newItem);
        }

        if (type === 'table' && columns && columns.length) {
          const newColumns = setTableColumnsFn(
            columns,
            hasSelection === null ? tableHasSelection : hasSelection,
            showAddAndDelBtn === null ? tableShowAddAndDelBtn : showAddAndDelBtn,
            routerType
          );

          newItem.columns = newColumns;

          detailList.value.push(newItem);
        }
        if (type === 'slot') {
          detailList.value.push(newItem);
        }
        // console.log(newItem);
      }

      // console.log(routerType);

      if (routerType !== 'add' && getDetailsFn && getDetailsFn.value) {
        // 获取详情数据
        const { params = {} } = route;

        const id = params[detailRouteParamsKey || 'id'];

        let getDetailsData = {
          [detailRouteParamsKey]: id,
        };

        if (setGetDetailsDataFn.value) {
          // 需要配置请求参数
          getDetailsData = await setGetDetailsDataFn.value(getDetailsData);
        }

        loading.value = true;

        try {
          const res = await getDetailsFn.value(getDetailsData);

          let rowData = null;

          nextTick(async () => {
            if (handleEditDetailsFn.value) {
              // 手动处理编辑数据
              rowData = await handleEditDetailsFn.value(res);
            } else {
              rowData = res[getDetailsFnDataKey];
            }

            detailsData = cloneDeep(res[getDetailsFnDataKey]);

            // console.log(rowData)

            if (rowData && detailRefList && detailRefList.length) {
              for (let i = 0; i < detailRefList.length; i++) {
                const { type = '', el = {}, name = '' } = detailRefList[i];

                if (type === 'form') {
                  if (routerType !== 'check') {
                    el.setFieldsValueFn && (await el.setFieldsValueFn(rowData, i));
                  } else {
                    const detailData = detailList.value[i];

                    if (
                      detailData &&
                      detailData.descriptionsSchemas &&
                      detailData.descriptionsSchemas.length
                    ) {
                      console.log(rowData);
                      for (const item of detailData.descriptionsSchemas) {
                        const {
                          label = null,
                          prop = null,
                          field = null,
                          checkPropFn = null,
                          checkProp = null,
                        } = item;

                        item['value'] = checkPropFn
                          ? await checkPropFn(rowData)
                          : rowData[checkProp || prop || field || label] || '';
                      }
                    }
                  }
                }

                if (type === 'table') {
                  el.setEditTableAllDataFn && (await el.setEditTableAllDataFn(rowData[name] || []));
                }
              }
            }

            setTimeout(() => {
              nextTick(() => {
                initData.value = getDetailRefListDataFn();

                loading.value = false;
              });
            }, 0);
          });
        } catch (e) {
          console.log(e);

          loading.value = false;
        }
      }

      setTimeout(() => {
        nextTick(() => {
          initData.value = getDetailRefListDataFn();
        });
      }, 0);

      // console.log(detailList);
    }
  }; // 数据初始化方法
  initFn(props);

  const setEditTableAllDataFn = async (elName, list) => {
    for (let i = 0; i < detailRefList.length; i++) {
      const { type = '', el = {}, name = '' } = detailRefList[i];

      if (elName === name && type === 'table') {
        console.log(list);
        el.setEditTableAllDataFn && (await el.setEditTableAllDataFn(list || []));
      }
    }
  };

  const getDataByName = (name = null) => {
    if (name) {
      let data: any = null;

      detailRefList.every((item) => {
        const { name: iName = null, type = null, el = null } = item;

        if (iName === name) {
          if (type === 'form') {
            data = el.getFieldsValueFn();
          }

          if (type === 'table') {
            data = el.getEditTableDataFn();
          }

          return false;
        }

        return true;
      });

      return data;
    }

    return null;
  };

  const getRefByName = (name = null) => {
    if (name) {
      let elObj: any = null;

      detailRefList.every((item) => {
        const { name: iName = null, el = null } = item;

        if (iName === name) {
          elObj = el;

          return false;
        }

        return true;
      });

      return elObj;
    }

    return null;
  };

  defineExpose({
    detailList,
    detailRefList,
    getDataByName,
    getRefByName,
    getDetailRefListDataFn,
    setEditTableAllDataFn,
  }); // 暴露现有组件方法
</script>

<style lang="less" scoped>
  .basicInfo {
    .n-icon {
      margin-right: 5px;
    }
    &-view {
      &-check {
        margin-top: 20px;
        &:first-child {
          margin-top: 0;
        }
      }
    }

    .df-descriptions {
      // padding-top: 24px;

      :deep(.file-list .file-item) {
        height: auto;
        line-height: inherit;
        background-color: transparent;
        margin-bottom: 0;
        margin-left: 0;
        padding-left: 0 !important;
        margin-right: 20px;
        padding-right: 0 !important;
        a {
          color: #1d6eff;
          &:hover {
            color: #1d6eff;
          }
        }
      }
    }
  }
</style>
